<?php
// +----------------------------------------------------------------------
// | QSCMS
// +----------------------------------------------------------------------
// | Copyright (c)  2025 https://www.qqss.net All rights reserved.
// +----------------------------------------------------------------------
// | Licensed QSCMS is not free software, commercial use must purchase official license from official website to avoid unnecessary legal disputes.
// +----------------------------------------------------------------------
// | Author: Contract 990504246@qq.com
// +----------------------------------------------------------------------

namespace app\adminapi\controller;

use app\common\model\UpgradeLog;

/**
 * 系统升级控制器 此文件为骑士多商户商城版本 暂未适配本系统
 */
class Upgrade extends Base
{
    /**
     * 检查升级
     */
    public function check()
    {
        // 获取当前系统版本
        $currentVersion = config('site.version');
        if (!$currentVersion) {
            return $this->error('获取当前系统版本失败');
        }

        // 调用远程API检查是否有新版本
        $api    = config('site.upgrade.api', 'https://www.qqss.net/api/upgrade/check');
        $params = [
            'version'   => $currentVersion,
            'site'      => $_SERVER['HTTP_HOST'] ?? '',
            'timestamp' => time()
        ];

        try {
            // 使用curl请求升级服务器
            $ch = curl_init();
            curl_setopt($ch, CURLOPT_URL, $api);
            curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
            curl_setopt($ch, CURLOPT_POST, 1);
            curl_setopt($ch, CURLOPT_POSTFIELDS, http_build_query($params));
            curl_setopt($ch, CURLOPT_TIMEOUT, 10);
            $response = curl_exec($ch);
            curl_close($ch);

            if (!$response) {
                return $this->error('连接升级服务器失败');
            }

            $result = json_decode($response, true);
            if (empty($result) || !isset($result['code'])) {
                return $this->error('升级服务器返回数据格式错误');
            }

            if ($result['code'] != 1) {
                return $this->error($result['msg'] ?? '检查更新失败');
            }

            // 返回升级信息
            return $this->success('获取升级信息成功', $result['data']);
        } catch (\Exception $e) {
            return $this->error('检查更新出错: ' . $e->getMessage());
        }
    }

    /**
     * 下载升级包
     */
    public function download()
    {
        $version = $this->request->post('version');
        $token   = $this->request->post('token');

        if (!$version || !$token) {
            return $this->error('参数错误');
        }

        try {
            // 创建下载目录
            $downloadDir = base_path(false) . DIRECTORY_SEPARATOR . 'runtime/upgrade/';
            if (!is_dir($downloadDir)) {
                mkdir($downloadDir, 0755, true);
            }

            // 下载文件名
            $fileName = 'upgrade_' . $version . '.zip';
            $savePath = $downloadDir . $fileName;

            // 下载升级包
            $api         = config('site.upgrade.download_api', 'https://www.qqss.net/api/upgrade/download');
            $downloadUrl = $api . '?version=' . $version . '&token=' . $token;

            $fp = fopen($savePath, 'w');
            $ch = curl_init();
            curl_setopt($ch, CURLOPT_URL, $downloadUrl);
            curl_setopt($ch, CURLOPT_FILE, $fp);
            curl_setopt($ch, CURLOPT_TIMEOUT, 3600); // 设置超时时间为1小时
            curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
            curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, false);
            $result = curl_exec($ch);
            if (!$result) {
                return $this->error('下载升级包失败: ' . curl_error($ch));
            }
            curl_close($ch);
            fclose($fp);

            // 记录日志
            UpgradeLog::create([
                'version'     => $version,
                'type'        => 'download',
                'status'      => 1,
                'message'     => '下载升级包成功',
                'create_time' => date('Y-m-d H:i:s')
            ]);

            return $this->success('下载升级包成功', [
                'file_path' => $savePath,
                'file_name' => $fileName,
                'file_size' => filesize($savePath)
            ]);
        } catch (\Exception $e) {
            // 记录日志
            UpgradeLog::create([
                'version'     => $version,
                'type'        => 'download',
                'status'      => 0,
                'message'     => '下载升级包失败: ' . $e->getMessage(),
                'create_time' => date('Y-m-d H:i:s')
            ]);

            return $this->error('下载升级包失败: ' . $e->getMessage());
        }
    }

    /**
     * 验证升级包
     */
    public function verify()
    {
        $version  = $this->request->post('version');
        $filePath = $this->request->post('file_path');

        if (!$version || !$filePath) {
            return $this->error('参数错误');
        }

        if (!file_exists($filePath)) {
            return $this->error('升级包文件不存在');
        }

        try {
            // 校验文件MD5
            $fileMd5 = md5_file($filePath);

            // 调用API验证MD5
            $api    = config('site.upgrade.verify_api', 'https://www.qqss.net/api/upgrade/verify');
            $params = [
                'version'   => $version,
                'md5'       => $fileMd5,
                'timestamp' => time()
            ];

            $ch = curl_init();
            curl_setopt($ch, CURLOPT_URL, $api);
            curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
            curl_setopt($ch, CURLOPT_POST, 1);
            curl_setopt($ch, CURLOPT_POSTFIELDS, http_build_query($params));
            curl_setopt($ch, CURLOPT_TIMEOUT, 10);
            $response = curl_exec($ch);
            curl_close($ch);

            if (!$response) {
                return $this->error('连接验证服务器失败');
            }

            $result = json_decode($response, true);
            if (empty($result) || !isset($result['code'])) {
                return $this->error('验证服务器返回数据格式错误');
            }

            if ($result['code'] != 1) {
                return $this->error($result['msg'] ?? '验证升级包失败');
            }

            // 记录日志
            UpgradeLog::create([
                'version'     => $version,
                'type'        => 'verify',
                'status'      => 1,
                'message'     => '验证升级包成功',
                'create_time' => date('Y-m-d H:i:s')
            ]);

            return $this->success('验证升级包成功');
        } catch (\Exception $e) {
            // 记录日志
            UpgradeLog::create([
                'version'     => $version,
                'type'        => 'verify',
                'status'      => 0,
                'message'     => '验证升级包失败: ' . $e->getMessage(),
                'create_time' => date('Y-m-d H:i:s')
            ]);

            return $this->error('验证升级包失败: ' . $e->getMessage());
        }
    }

    /**
     * 升级系统
     */
    public function upgrade()
    {
        $version  = $this->request->post('version');
        $filePath = $this->request->post('file_path');
        $backup   = $this->request->post('backup', 1); // 是否备份

        if (!$version || !$filePath) {
            return $this->error('参数错误');
        }

        if (!file_exists($filePath)) {
            return $this->error('升级包文件不存在');
        }

        try {
            // 记录开始升级日志
            UpgradeLog::create([
                'version'     => $version,
                'type'        => 'upgrade',
                'status'      => 1,
                'message'     => '开始准备升级系统',
                'create_time' => date('Y-m-d H:i:s')
            ]);

            // 创建解压目录
            $extractDir = base_path(false) . DIRECTORY_SEPARATOR . 'runtime/upgrade/extract_' . $version . '/';
            if (!is_dir($extractDir)) {
                mkdir($extractDir, 0755, true);
            } else {
                // 清空目录
                $this->clearDir($extractDir);
            }

            // 解压升级包
            $zip = new \ZipArchive();
            if ($zip->open($filePath) !== true) {
                throw new \Exception('无法打开升级包文件');
            }
            $zip->extractTo($extractDir);
            $zip->close();

            // 检查升级包中的upgrade.php和upgrade.sql
            $upgradeScript = $extractDir . 'upgrade.php';
            $upgradeSql    = $extractDir . 'upgrade.sql';

            // 创建完整的外部升级脚本
            $scriptPath = $this->createUpgradeScript($upgradeScript, $upgradeSql, $extractDir, $version, $backup);

            // 返回升级脚本路径，前端将调用此脚本执行实际升级
            return $this->success('系统准备升级完成，请执行升级脚本完成升级', [
                'script_path' => $scriptPath,
                'version'     => $version
            ]);
        } catch (\Exception $e) {
            // 记录失败日志
            UpgradeLog::create([
                'version'     => $version,
                'type'        => 'upgrade',
                'status'      => 0,
                'message'     => '准备升级系统失败: ' . $e->getMessage(),
                'create_time' => date('Y-m-d H:i:s')
            ]);

            return $this->error('准备升级系统失败: ' . $e->getMessage());
        }
    }

    /**
     * 创建升级脚本
     * @param string $upgradePhpPath 自定义升级PHP脚本路径
     * @param string $upgradeSqlPath 升级SQL脚本路径
     * @param string $extractDir 解压目录
     * @param string $version 版本号
     * @param bool $backup 是否备份
     * @return string 生成的脚本路径
     */
    protected function createUpgradeScript($upgradePhpPath, $upgradeSqlPath, $extractDir, $version, $backup)
    {
        // 创建脚本目录
        $scriptDir = base_path(false) . DIRECTORY_SEPARATOR . 'runtime/upgrade/scripts/';
        if (!is_dir($scriptDir)) {
            mkdir($scriptDir, 0755, true);
        }

        // 获取绝对路径
        $rootPath = rtrim(base_path(false) . DIRECTORY_SEPARATOR, '/\\');

        // 获取数据库配置
        $config   = config('database.connections.mysql');
        $dbName   = $config['database'];
        $username = $config['username'];
        $password = $config['password'];
        $host     = $config['hostname'];
        $port     = $config['hostport'];
        $charset  = $config['charset'];

        if (PHP_OS == 'WINNT') {
            // Windows平台 - .bat文件
            $scriptName = 'upgrade_' . date('YmdHis') . '.bat';
            $scriptPath = $scriptDir . $scriptName;

            $content = "@echo off\r\n";
            $content .= "echo ======================================\r\n";
            $content .= "echo 系统升级脚本 - 版本 " . $version . "\r\n";
            $content .= "echo ======================================\r\n";

            if ($backup) {
                $content .= "echo 正在备份系统...\r\n";
                $backupDir = $rootPath . "\\runtime\\backup\\" . date('Ymd_His') . "\\";
                $content .= "mkdir \"" . $backupDir . "\"\r\n";
                $content .= "mkdir \"" . $backupDir . "app\"\r\n";
                $content .= "mkdir \"" . $backupDir . "config\"\r\n";
                $content .= "mkdir \"" . $backupDir . "public\"\r\n";

                $content .= "xcopy \"" . $rootPath . "\\app\" \"" . $backupDir . "app\" /E /Y /I\r\n";
                $content .= "xcopy \"" . $rootPath . "\\config\" \"" . $backupDir . "config\" /E /Y /I\r\n";
                $content .= "xcopy \"" . $rootPath . "\\public\" \"" . $backupDir . "public\" /E /Y /I\r\n";

                // 备份数据库
                $content .= "echo 正在备份数据库...\r\n";
                $dbBackupFile = $backupDir . "db_backup_" . date('YmdHis') . ".sql";
                $content .= "mysqldump --opt --host=" . $host . " --port=" . $port . " --user=" . $username . " --password=" . $password . " --default-character-set=" . $charset . " " . $dbName . " > \"" . $dbBackupFile . "\"\r\n";
            }

            // 如果有SQL脚本，执行它
            if (file_exists($upgradeSqlPath)) {
                $content .= "echo 正在执行SQL升级脚本...\r\n";
                $content .= "mysql --host=" . $host . " --port=" . $port . " --user=" . $username . " --password=" . $password . " --default-character-set=" . $charset . " " . $dbName . " < \"" . $upgradeSqlPath . "\"\r\n";
            }

            $content .= "echo 正在停止webman服务...\r\n";
            $content .= "cd /d \"" . $rootPath . "\"\r\n";
            $content .= "php webman stop\r\n";
            $content .= "timeout /t 3\r\n"; // 等待3秒确保服务停止

            $content .= "echo 正在复制文件...\r\n";
            // 复制文件使用绝对路径
            $content .= "xcopy \"" . rtrim($extractDir, '/\\') . "\\app\" \"" . $rootPath . "\\app\" /E /Y /I\r\n";
            $content .= "xcopy \"" . rtrim($extractDir, '/\\') . "\\config\" \"" . $rootPath . "\\config\" /E /Y /I\r\n";
            $content .= "xcopy \"" . rtrim($extractDir, '/\\') . "\\public\" \"" . $rootPath . "\\public\" /E /Y /I\r\n";

            // 如果有自定义升级脚本，执行它
            if (file_exists($upgradePhpPath)) {
                $content .= "echo 执行自定义升级脚本...\r\n";
                $content .= "php \"" . $upgradePhpPath . "\"\r\n";
            }

            // 启动webman服务
            $content .= "echo 正在启动webman服务...\r\n";
            $content .= "php webman start -d\r\n";

            // 更新版本号
            $content .= "echo 更新系统版本号...\r\n";
            $content .= "cd /d \"" . $rootPath . "\"\r\n";
            $content .= "php webman run \"\\app\\command\\UpdateVersion --version=" . $version . "\"\r\n";

            $content .= "echo ======================================\r\n";
            $content .= "echo 系统升级完成！当前版本：" . $version . "\r\n";
            $content .= "echo ======================================\r\n";
            $content .= "pause\r\n";
        } else {
            // Linux/Unix平台 - .sh文件
            $scriptName = 'upgrade_' . date('YmdHis') . '.sh';
            $scriptPath = $scriptDir . $scriptName;

            $content = "#!/bin/bash\n";
            $content .= "echo \"======================================\"\n";
            $content .= "echo \"系统升级脚本 - 版本 " . $version . "\"\n";
            $content .= "echo \"======================================\"\n";

            if ($backup) {
                $content .= "echo \"正在备份系统...\"\n";
                $backupDir = $rootPath . "/runtime/backup/" . date('Ymd_His') . "/";
                $content .= "mkdir -p \"" . $backupDir . "app\"\n";
                $content .= "mkdir -p \"" . $backupDir . "config\"\n";
                $content .= "mkdir -p \"" . $backupDir . "public\"\n";

                $content .= "cp -rf \"" . $rootPath . "/app\" \"" . $backupDir . "\"\n";
                $content .= "cp -rf \"" . $rootPath . "/config\" \"" . $backupDir . "\"\n";
                $content .= "cp -rf \"" . $rootPath . "/public\" \"" . $backupDir . "\"\n";

                // 备份数据库
                $content .= "echo \"正在备份数据库...\"\n";
                $dbBackupFile = $backupDir . "db_backup_" . date('YmdHis') . ".sql";
                $content .= "mysqldump --opt --host=\"" . $host . "\" --port=" . $port . " --user=\"" . $username . "\" --password=\"" . $password . "\" --default-character-set=" . $charset . " " . $dbName . " > \"" . $dbBackupFile . "\"\n";
            }

            // 如果有SQL脚本，执行它
            if (file_exists($upgradeSqlPath)) {
                $content .= "echo \"正在执行SQL升级脚本...\"\n";
                $content .= "mysql --host=\"" . $host . "\" --port=" . $port . " --user=\"" . $username . "\" --password=\"" . $password . "\" --default-character-set=" . $charset . " " . $dbName . " < \"" . $upgradeSqlPath . "\"\n";
            }

            $content .= "echo \"正在停止webman服务...\"\n";
            $content .= "cd \"" . $rootPath . "\"\n";
            $content .= "php webman stop\n";
            $content .= "sleep 3\n"; // 等待3秒确保服务停止

            $content .= "echo \"正在复制文件...\"\n";
            // 复制文件使用绝对路径
            $content .= "cp -rf \"" . rtrim($extractDir, '/') . "/app\"/* \"" . $rootPath . "/app/\"\n";
            $content .= "cp -rf \"" . rtrim($extractDir, '/') . "/config\"/* \"" . $rootPath . "/config/\"\n";
            $content .= "cp -rf \"" . rtrim($extractDir, '/') . "/public\"/* \"" . $rootPath . "/public/\"\n";

            // 如果有自定义升级脚本，执行它
            if (file_exists($upgradePhpPath)) {
                $content .= "echo \"执行自定义升级脚本...\"\n";
                $content .= "php \"" . $upgradePhpPath . "\"\n";
            }

            // 启动webman服务
            $content .= "echo \"正在启动webman服务...\"\n";
            $content .= "php webman start -d\n";

            // 更新版本号
            $content .= "echo \"更新系统版本号...\"\n";
            $content .= "cd \"" . $rootPath . "\"\n";
            $content .= "php webman run \"\\app\\command\\UpdateVersion --version=" . $version . "\"\n";

            $content .= "echo \"======================================\"\n";
            $content .= "echo \"系统升级完成！当前版本：" . $version . "\"\n";
            $content .= "echo \"======================================\"\n";
        }

        // 写入脚本文件
        file_put_contents($scriptPath, $content);

        // 如果是Linux/Unix，设置执行权限
        if (PHP_OS != 'WINNT') {
            chmod($scriptPath, 0755);
        }

        return $scriptPath;
    }

    /**
     * 获取升级日志
     */
    public function logs()
    {
        $page  = $this->request->post('page', 1);
        $limit = $this->request->post('limit', 20);

        $list = UpgradeLog::order('id', 'desc')
            ->paginate([
                'list_rows' => $limit,
                'page'      => $page
            ]);

        return $this->success('获取成功', $list);
    }

    /**
     * 清理升级文件
     */
    public function clean()
    {
        try {
            // 清理临时文件
            $tempDirs = [
                base_path(false) . DIRECTORY_SEPARATOR . 'runtime/upgrade/',
            ];

            foreach ($tempDirs as $dir) {
                if (is_dir($dir)) {
                    $this->clearDir($dir);
                }
            }

            return $this->success('清理成功');
        } catch (\Exception $e) {
            return $this->error('清理失败: ' . $e->getMessage());
        }
    }

    /**
     * 修改版本号
     */
    public function updateVersion()
    {
        $version = $this->request->post('version');

        if (!$version) {
            return $this->error('参数错误');
        }

        try {
            // 更新配置文件中的版本号
            $configFile = config_path() . 'site.php';
            if (!file_exists($configFile)) {
                return $this->error('配置文件不存在');
            }

            $config = file_get_contents($configFile);
            $config = preg_replace("/'version'\s*=>\s*'.*?'/", "'version' => '" . $version . "'", $config);
            file_put_contents($configFile, $config);

            return $this->success('版本号更新成功');
        } catch (\Exception $e) {
            return $this->error('版本号更新失败: ' . $e->getMessage());
        }
    }

    /**
     * 清空目录
     * @param string $dir 目录路径
     */
    protected function clearDir($dir)
    {
        if (!is_dir($dir)) {
            return;
        }

        $files = scandir($dir);
        foreach ($files as $file) {
            if ($file == '.' || $file == '..') {
                continue;
            }

            $path = $dir . '/' . $file;
            if (is_dir($path)) {
                $this->clearDir($path);
                rmdir($path);
            } else {
                unlink($path);
            }
        }
    }
}